#include "TablaHash.h"
#include "../common/SerialInator.h"



TablaHash::TablaHash() : tabDispersion(4, 1)
{
	// Se inicializa con tamaño 4 todos apuntando al primer bloque
}


int TablaHash::dispersar(const RegistroHash& reg) const{
	return reg.getClave() % this->tabDispersion.size();
}


unsigned int TablaHash::getPosBloque(const RegistroHash& reg) const{
	int i = dispersar(reg);

	// Se devuelve la posicion en disco del bloque correspondiente
	return tabDispersion[i];
}


void TablaHash::overflowBloque(const RegistroHash& regOver, const BloqueHash& bloque, unsigned int posNewBloque){
	// Si el tamaño de dispersion del bloque que hizo overflow es igual al tamaño de la tabla
	if (bloque.getTamDispersion() == this->tabDispersion.size()){
		// Se duplica la tabla
		duplicarTabla();
	}

	// Se agregan las referencias al nuevo bloque

	// Se reemplazan las referencias al bloque con las referencias al nuevo bloque en forma circular
	int tamSalto = bloque.getTamDispersion() *2;
	unsigned int posIni = dispersar(regOver);
	unsigned int i = posIni;
	do {
		// Se reemplaza la referencia
		this->tabDispersion[i] = posNewBloque;

		// Salta
		i += tamSalto;

		// Se chequea que no caiga afuera de la tabla
		if (i >= this->tabDispersion.size()){
			i -= this->tabDispersion.size();
		}

	} while (i != posIni);
}


void TablaHash::duplicarTabla(){
	// Una copia de la tabla actual
	std::vector<unsigned int> vecTemp(this->tabDispersion);

	// Se reserva el espacio para los nuevos elementos y se los copia
	vecTemp.reserve(this->tabDispersion.size() * 2);
	vecTemp.insert(vecTemp.end(), this->tabDispersion.begin(), this->tabDispersion.end());

	// Cambia el contenido del vec temporal con la tabla de dispersion real
	this->tabDispersion.swap(vecTemp);
}


int TablaHash::serializar(char* arrBytes){
	SerialInator s;
	s.reset();

	// Primero la cantidad de elementos
	unsigned short int cant = this->tabDispersion.size();
	s.serializar(arrBytes, cant);

	std::vector<unsigned int>::const_iterator it;
	for (it = this->tabDispersion.begin(); it != this->tabDispersion.end(); ++it){
		s.serializar(arrBytes, *it);
	}
	
	return s.getBufferSize();
}


int TablaHash::desSerializar(char* arrBytes){
	SerialInator s;
	s.reset();
	this->tabDispersion.clear();	// Limpia la tabla

	// Cantidad de elementos
	unsigned short int cant = 0;
	s.desSerializar(arrBytes, cant);

	// Recupera todos los elementos
	this->tabDispersion.reserve(cant);
	for (int i = 0; i < cant; ++i){
		unsigned int temp = 0;
		s.desSerializar(arrBytes, temp);
		this->tabDispersion.push_back(temp);
	}
	
	return s.getBufferSize();
}





